package jee.boot.common.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jee.boot.common.basic.CrudService;
import jee.boot.common.basic.DataEntity;
import jee.boot.common.basic.ServiceException;
import jee.boot.common.basic.result.MapData;
import jee.boot.entity.auth.Account;
import jee.boot.entity.system.Filter;
import jee.boot.common.remote.RemoteEndpoint;
import jee.boot.common.utils.StringUtils;
import jee.boot.common.dao.TreeAsignSituationDao;
import jee.boot.common.dao.TreeModelDao;
import jee.boot.common.dao.TreeNodeDao;
import jee.boot.entity.system.TreeModel;
import jee.boot.entity.system.TreeNode;
import org.assertj.core.util.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 树节点
 */
@Service
public class TreeNodeService extends CrudService<TreeNodeDao, TreeNode> {
    public static final String TREE_ROOT_ID = "root_id";
    @Autowired
    private TreeModelDao treeModelDao;
    @Autowired
    private TreeAsignSituationDao treeAsignSituationDao;
    @Autowired
    private RemoteEndpoint remoteEndpoint;

    /**
     * 保存树节点,自动赋值层级数据
     *
     * @param entity
     */
    @Override
    public void save(TreeNode entity) {
        // 如果没有设置父节点，则代表为跟节点
        if (entity.getParent() == null || StringUtils.isBlank(entity.getParent().getId())) {
            entity.setTier(TreeNode.TREE_FIRST_TIER);
            entity.setPath(TreeNode.TREE_PATH_SEPARATOR);
            entity.setParent(new TreeNode(TREE_ROOT_ID));
        } else {
            TreeNode parent = super.get(entity.getParent());
            if (parent == null) {
                throw new ServiceException(1301, MapData.instance().put("parentId", entity.getParent().getId()).data());
            }
            entity.setParent(parent);
            entity.setTier(parent.getTier() + 1);//当前节点增加一个层级
            entity.setPath(parent.getPath() + TreeNode.TREE_PATH_SEPARATOR + parent.getId());
        }
        // 检查规则约束
        check(entity);
        // 保存实体
        super.save(entity);
    }

    /**
     * 修改树节点:如果修改当前节点的在树上的位置,则会级联更新这个节点以及所有子节点的位置
     *
     * @param entity
     */
    @Override
    public void update(TreeNode entity) {
        // 获取修改前的Path，用于更新子节点的Path
        String oldPath = entity.getPath();
        // 如果没有设置父节点，则代表为跟节点
        if (entity.getParent() == null) {
            entity.setTier(TreeNode.TREE_FIRST_TIER);
            entity.setPath(TreeNode.TREE_PATH_SEPARATOR);
        } else {
            TreeNode parent = super.get(entity.getParent());
            if (parent == null) {
                throw new ServiceException(1301, MapData.instance().put("parentId", entity.getParent().getId()).data());
            }
            entity.setParent(parent);
            entity.setTier(parent.getTier() + 1);//当前节点增加一个层级
            entity.setPath(parent.getPath() + TreeNode.TREE_PATH_SEPARATOR + parent.getId());//设置新的path
        }
        // 检查规则约束
        check(entity);
        // 更新实体
        super.update(entity);
        // 更新子节点 path
        TreeNode children = new TreeNode();
        children.addFilter(new Filter("path", "like", TreeNode.TREE_PATH_SEPARATOR + entity.getId()));
        List<TreeNode> list = dao.findList(children);
        for (TreeNode child : list) {
            // 原始path为"/"表示原来是根节点,只需要在child的前面拼接上entity的path即可
            if (StringUtils.equals(oldPath, TreeNode.TREE_PATH_SEPARATOR)) {
                child.setPath(entity.getPath() + child.getPath());
            } else {//否则将新旧的path部分替换为新的path部分
                child.setPath(child.getPath().replace(oldPath, entity.getPath()));
            }
            //根据层级,根据每个path里的分隔符个数来设定层级
            child.setTier(StringUtils.split(child.getPath(), TreeNode.TREE_PATH_SEPARATOR).length + 1);
            // 检查规则约束
            check(child);
            dao.update(child);
        }
    }

    @Override
    public void delete(TreeNode entity) {
        super.delete(entity);
        // 删除所有子节点
        TreeNode children = new TreeNode();
        children.addFilter(new Filter("path", "like", TreeNode.TREE_PATH_SEPARATOR + entity.getId()));
        List<TreeNode> list = dao.findList(children);
        if (list != null && !list.isEmpty()) {
            for (TreeNode del : list) {
                dao.delete(del);
            }
        }
    }

    /**
     * 检查是否存在规则约束
     *
     * @param treeNode
     */
    private void check(TreeNode treeNode) {
        TreeNode parent = treeNode.getParent();//treeNode的父节点
        // 检查父节点模型约束
        if (parent != null && StringUtils.isNotBlank(parent.getId())) {
            TreeModel treeModel = treeModelDao.get(treeNode.getTreeModel());//当前节点模型(肯定存在),重新查询一遍主要是为了把他的parent关联出来
            TreeModel parentTreeModel = parent.getTreeModel();//父节点模型(肯定存在)
            TreeModel treeModelParentModel = treeModel.getParent();//当前节点模型的父模型定义(不一定存在)

            if (treeModelParentModel != null && parentTreeModel != null) {
                if (!StringUtils.equals(treeModelParentModel.getId(), parentTreeModel.getId())) {
                    throw new ServiceException(1302, MapData.instance().put("treeModelName", treeModel.getName()).put("treeParentModelName", treeModelParentModel.getName()).data());
                }
            }
        }
//        // 检查层级约束
//        Integer treeNodeTier = treeNode.getTreeModel().getTreeNodeTier();
//        if (treeNodeTier != null) {
//            if (!treeNodeTier.equals(treeNode.getTier())) {
//                throw new ServiceException(1303, MapData.instance().put("treeModelName", treeNode.getTreeModel().getName()).put("treeNodeTier", treeNodeTier).data());
//            }
//        }
    }

    /**
     * 基础的必填校验
     *
     * @param treeNode
     */
    private void checkData(TreeNode treeNode) {
        // 树情景定义暂时不需要,这里先不校验了,需要校验的时候再加
//        TreeAsignSituation treeAsignSituation = treeNode.getTreeAsignSituation();
//        if(treeAsignSituation==null){
//            throw new ServiceException(1304);
//        }
//        TreeModel treeModel = treeNode.getTreeModel();
//        if(treeModel==null){
//            // 如果页面忘记传值,可以从情景定义中获取模型
//            TreeAsignSituation treeAsignSituation1 = treeAsignSituationDao.get(treeAsignSituation);
//            treeNode.setTreeModel(treeAsignSituation1.getTreeModel());
//        }
    }

    /**
     * 建树
     *
     * @param list
     * @return
     */
    public List<TreeNode> buildTree(List<TreeNode> list) {
        List<TreeNode> retList = new ArrayList<TreeNode>();
        for (TreeNode child : list) {
            boolean hasParent = false;
            for (TreeNode parent : list) {
                if (child.getParent() != null && StringUtils.equals(child.getParent().getId(), parent.getId())) {
                    parent.getChildren().add(child);
                    hasParent = true;
                }
            }
            if (!hasParent) {
                retList.add(child);
            }
        }
        sort(retList);// 排序
        return retList;
    }

    /**
     * 排序
     *
     * @param list
     */
    protected void sort(List<TreeNode> list) {
        if (list != null && !list.isEmpty()) {
            Collections.sort(list, new Comparator<TreeNode>() {
                public int compare(TreeNode a, TreeNode b) {
                    Integer sorta = a.getTier() == null ? 0 : a.getTier();
                    Integer sortb = b.getTier() == null ? 0 : b.getTier();
                    return sorta.compareTo(sortb);
                }
            });
            for (TreeNode child : list) {
                sort(child.getChildren());
            }
        }
    }

    public void update1() {
        List<TreeNode> list = findList(new TreeNode());
        list.forEach(treeNode -> {
            String a = treeNode.getPath();
            String path = StringUtils.substringBeforeLast(a, "/");
            String parentId = StringUtils.substringAfterLast(path, "/");
            treeNode.setPath(path);
            treeNode.setParent(new TreeNode(parentId));
            super.update(treeNode);
        });

    }

    public static void main1(String[] args) {
        String a = "/a/b";
        String path = StringUtils.substringBeforeLast(a, "/");
        String parentId = StringUtils.substringAfterLast(path, "/");
        System.out.println(path);
        System.out.println(parentId);
    }

    public List<TreeNode> treeData(TreeNode entity) {
        List<TreeNode> list = super.findList(entity);
        List<TreeNode> tree = buildTree(list);
        if (entity.isFullPath()) {
            Set<String> parentIds = findAllParentIds(tree);
            if (!parentIds.isEmpty()) {
                // 忽略权限拦截查询所有的父节点
                List<TreeNode> parentList = dao.findList(new TreeNode().addFilter(new Filter("id", "in", StringUtils.join(parentIds, ","))));
                // 添加父节点到当前的结果列表中
                list.addAll(parentList);
                return buildTree(list);
            }
        }
        return tree;
    }

    /**
     * 取出所有父节点的ids
     *
     * @param tree
     * @return
     */
    public Set<String> findAllParentIds(List<TreeNode> tree) {
        Set<String> parentIds = Sets.newHashSet();
        if (tree != null && !tree.isEmpty()) {
            tree.stream().forEach(treeNode -> {
                String[] split = StringUtils.split(treeNode.getPath(), "/");
                if (split != null && split.length > 0) {
                    parentIds.addAll(Arrays.asList(split));
                }
            });
        }
        return parentIds;
    }

    @Override
    public List<TreeNode> findList(TreeNode entity) {
        List<String> allIds = Lists.newArrayList();
        List<TreeNode> authList = getAuthList(entity);
        List<TreeNode> authRootList = buildTree(authList);
        List<String> pathIds = getPathList(authList);
        Set<String> authIds = authList.stream().map(d -> d.getId()).collect(Collectors.toSet());
        Set<String> authRootIds = authRootList.stream().map(d -> d.getId()).collect(Collectors.toSet());
        allIds.addAll(authIds);
        allIds.addAll(pathIds);
        // 不经过权限,查询出所有的权限内的节点+path节点
        entity.addFilter(new Filter("id", "in", allIds));

        List<TreeNode> list = dao.findList(entity);

        if (list != null && !list.isEmpty()) {
            list.forEach(d -> {
                if (authIds.contains(d.getId())) {
                    if (authRootIds.contains(d.getId())) {
                        d.setHasAuth("rootAuth");
                    } else {
                        d.setHasAuth("childAuth");
                    }
                }
            });
        }

        if (entity.isCascadeEntity()) {
            queryEntity(list);
        }
        return list;
    }

    /**
     * 获取权限内的所有节点+各个根节点的path节点
     *
     * @param entity
     * @return
     */
    private List<TreeNode> getAuthList(TreeNode entity) {
        // 先查询出权限内的所有节点(不包含页面的查询条件)
        return super.findList(new TreeNode());
    }

    /**
     * 获取权限内的所有节点+各个根节点的path节点
     *
     * @param authList
     * @return
     */
    private List<String> getPathList(List<TreeNode> authList) {
        List<String> retList = Lists.newArrayList();

        if (authList != null && !authList.isEmpty()) {
            // 对权限内的数据转换为树,取出所有的根节点
            List<TreeNode> rootList = buildTree(authList);
            // 取出所有的父节点中的ids
            Set<String> parentIds = findAllParentIds(rootList);

            retList.addAll(parentIds);
        }
        return retList;
    }

    /**
     * 查询实体数据
     *
     * @param list
     */
    private void queryEntity(List<TreeNode> list) {
        // key,value => model.url,List<entityId>
        Map<String, List<String>> map = Maps.newHashMap();
        // key,value => treeNode.entityId,TreeNode
        Map<String, TreeNode> mapNode = Maps.newHashMap();

        if (list != null && !list.isEmpty()) {
            list.stream().forEach(node -> {
                mapNode.put(node.getEntityId(), node);
                TreeModel treeModel = node.getTreeModel();
                List<String> ids = map.get(treeModel.getUrl());
                if (ids == null) {
                    ids = Lists.newArrayList();
                    map.put(treeModel.getUrl(), ids);
                }
                ids.add(node.getEntityId());
            });
        }
        map.forEach((key, ids) -> {
            Account account = new Account().addFilter(new Filter("id", "in", StringUtils.join(ids, ",")));
            Map<String, Object> param = MapData.instance().put("filter", account.getFilter()).data();
            //这里默认就只认为是在相同服务里了,不考虑多个服务了
            // /system/org/list => /org/list/inner
            String path = StringUtils.substring(key, StringUtils.indexOf(key, "/", 2)) + "/inner";
            List<DataEntity> listData = remoteEndpoint.executePost("", path, param, List.class);
            for (DataEntity entity : listData) {
                TreeNode treeNode = mapNode.get(entity.getId());
                if (treeNode != null) {
                    treeNode.setEntity(entity);
                }
            }
        });

    }

    public static void main(String[] args) {
        String key = "/system/org/list";
        System.out.println(StringUtils.substring(key, StringUtils.indexOf(key, "/", 2)));
    }
}
